/*****************************************************************************
*    Copyright (C)2008 Ali Corporation. All Rights Reserved.
*
*    File:    smsc9220.c
*
*    Description:    SMSC LAN9220 NIC Driver From Linux.
*
*    History:
*		Date			Athor		Version		Reason
*	    =======================================================
*	1.	12.23.2008	Mao Feng		Ver 0.1		Create
*	2.	05.08.2009							Support Both 3329 & 3602
*
******************************************************************************/
#include <osal/osal.h>
#include <basic_types.h>

#include <api/libc/alloc.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>

#include <hld/hld_dev.h>

#include <hld/net/net.h>
#include <hld/net/ethtool.h>
#include <hal/hal_gpio.h>

UINT32 ATA_IO_BASE;
#include "smsc9220.h"
#include "smsc9220_reg.h"

//GPIO-Address
UINT8 SMSC9220_GPIO = 7; //lan_int
UINT8 SMSC9220_POLAR = 0; //int polar

UINT8 SMSC_FIFO_SEL = 36; //fifo_sel

UINT8 SMSC_ADDR7 = 6; //lan_a7
extern UINT8 g_smsc_addr7;

#ifdef SMSC_UP_BUS
extern UINT32 smsc_spe_map;
extern UINT8 smsc_spe_id;

#else //SMSC_UP_BUS
UINT8 SMSC_CS = 10; //lan_a5

UINT8 SMSC_ADDR6 = 61; //lan_a6
extern UINT8 g_smsc_addr6;

//mutex id for CI & ATA DMA op.
extern struct smsc_mutex smsc_mutex_id;

#endif//SMSC_UP_BUS

PPRIVATE_DATA g_pAdapter = NULL;

static UINT8 smsc9220_name[HLD_MAX_NAME_SIZE] = "SMSC9220_0";

//88h register settings.
volatile UINT32 g_GpioSetting=(GPIO_CFG_LED1_EN_|GPIO_CFG_LED2_EN_);
volatile UINT32 g_GpioSettingOriginal=(GPIO_CFG_LED1_EN_|GPIO_CFG_LED2_EN_);

//global options.
UINT32 int_deas=0x22UL;	//Int De-assertion interval.

#define TX_FIFO_LOW_THRESHOLD	(1600)

UINT32 smsc_r32(UINT32 addr);
void smsc_w32(UINT32 addr,UINT32 data);
void smsc_WriteDataFifo(PPRIVATE_DATA pAdapter, void *buf, UINT16 len);
void smsc_ReadDataFifo(UINT32 transfer, UINT32 *pdwBuf, UINT32 dwDwordCount);
void smsc_mutex_init(void);

#define Lan_GetRegDW(dwOffset)	\
	smsc_r32(dwOffset)

#define Lan_SetRegDW(dwOffset,dwVal)	\
	smsc_w32(dwOffset,dwVal)

#define Lan_ClrBitsDW(dwOffset,dwBits)	\
	smsc_w32(dwOffset,smsc_r32(dwOffset)&(~dwBits))

#define Lan_SetBitsDW(dwOffset,dwBits)	\
	smsc_w32(dwOffset,smsc_r32(dwOffset)|dwBits)

//Debug Use.
void Lan_PrintBuf(UINT8 *p, UINT32 len)
{
	UINT32 i,label=0,count=0;

	SMSC_TRACE("buffer addr: %x\n", p);
	for(i=0;i<len;i++)
	{
		if(!(i%16))
		{
			SMSC_TRACE("\n");
			label = 1;
		}
		if(label)
		{
			SMSC_TRACE("%08x   ",count);
			count+=16;
			label = 0;
		}
			SMSC_TRACE("%02x ",p[i]);
	}
	SMSC_TRACE("\n");
}


void Lan_MutexLock(OSAL_ID mutex_id)
{
	SMSC_ASSERT(OSAL_INVALID_ID!=mutex_id);
	osal_mutex_lock(mutex_id, OSAL_WAIT_FOREVER_TIME);
}


void Lan_MutexUnlock(OSAL_ID mutex_id)
{
	SMSC_ASSERT(OSAL_INVALID_ID!=mutex_id);	
	osal_mutex_unlock(mutex_id);
}


UINT32 Lan_RegGetPrint(UINT32 addr)
{
	UINT32 tmp_32 = Lan_GetRegDW(addr);
	
	SMSC_TRACE("=>Smsc io Reg 0x%02x : 0x%08x.\n", addr, tmp_32);

	return tmp_32;
}


void Lan_RegTest()
{
	UINT16 tmp_16;
	UINT32 tmp_32;
	int i;

	//Smsc io Regs test
	SMSC_TRACE("Smsc io Regs Write&Read Test: \n");
	
	for(i = 0x00; i < 0xb8; i += 4)
	{
		if(1)
		{
			//smsc_r32(i);
			SMSC_TRACE("=>Smsc io Reg 0x%02x : 0x%08x.\n", i, smsc_r32(i));
		}
		else
		{
			SMSC_TRACE("=>Smsc io Reg 0x%02x : 0x%08x", i, smsc_r32(i));
			smsc_w32(i, 0x00000000);
			SMSC_TRACE("=======>after write 0 : 0x%08x", smsc_r32(i));
			smsc_w32(i, 0xffffffff);
			SMSC_TRACE("=======>after write 1 : 0x%08x. \n", smsc_r32(i));
		}
	}

	osal_task_sleep(1000);
	//asm("sdbbp");

}


RET_CODE
Lan_Reset(PPRIVATE_DATA pAdapter)
{
	UINT32 dwTimeOut=0;
	UINT32 dwTemp=0;
	UINT32 dwResetCount=1;	
	int i;
	
	while(dwResetCount>0) 
	{
		//SMSC_WARNING("%s()=>HW_CFG(0x%x).\n", __FUNCTION__, Lan_GetRegDW(HW_CFG));
		Lan_SetRegDW(HW_CFG,HW_CFG_SRST_|HW_CFG_SF_);
		
		dwTimeOut=10;	// 1s ?
		do {
			osal_task_sleep(100);
			dwTemp=Lan_GetRegDW(HW_CFG);
			SMSC_WARNING("%s()=>HW_CFG(0x%x).\n", __FUNCTION__, dwTemp);
			dwTimeOut--;
		} while((dwTimeOut>0)&&(dwTemp&HW_CFG_SRST_));
		if(dwTemp&HW_CFG_SRST_) {
			SMSC_WARNING("%s()=>Failed to complete reset.\n", __FUNCTION__);
			return ERR_FAILED;
		}
		dwResetCount--;
	}

	return SUCCESS;
}


/*
Step 1=>Chip Reset
Step 2=>Hw Config(HW_CFG AFC_CFG)
Step 3=>GPIO Config(GPIO_CFG)
*/
RET_CODE
Lan_Initialize(PPRIVATE_DATA pAdapter)
{
	RET_CODE ret;
	UINT32 dwTxFifSz = pAdapter->TxFifoSize;
	UINT32 dwAfcCfg = pAdapter->AfcConfig;
	UINT32 dwIntCfg = pAdapter->InterruptConfig;
	UINT32 dwTimeOut=0;

	ret = Lan_Reset(pAdapter);
	if(SUCCESS != ret)
		return ret;

	SMSC_ASSERT(dwTxFifSz>=0x00020000UL);
	SMSC_ASSERT(dwTxFifSz<=0x000E0000UL);
	SMSC_ASSERT((dwTxFifSz&(~HW_CFG_TX_FIF_SZ_))==0);
	Lan_SetRegDW(HW_CFG,dwTxFifSz);
	
	pAdapter->RxMaxDataFifoSize=0;
	switch(dwTxFifSz>>16) 
	{
		case 2:pAdapter->RxMaxDataFifoSize=13440;break;
		case 3:pAdapter->RxMaxDataFifoSize=12480;break;
		case 4:pAdapter->RxMaxDataFifoSize=11520;break;
		case 5:pAdapter->RxMaxDataFifoSize=10560;break;
		case 6:pAdapter->RxMaxDataFifoSize=9600;break;
		case 7:pAdapter->RxMaxDataFifoSize=8640;break;
		case 8:pAdapter->RxMaxDataFifoSize=7680;break;
		case 9:pAdapter->RxMaxDataFifoSize=6720;break;
		case 10:pAdapter->RxMaxDataFifoSize=5760;break;
		case 11:pAdapter->RxMaxDataFifoSize=4800;break;
		case 12:pAdapter->RxMaxDataFifoSize=3840;break;
		case 13:pAdapter->RxMaxDataFifoSize=2880;break;
		case 14:pAdapter->RxMaxDataFifoSize=1920;break;
		default:SMSC_ASSERT(FALSE);break;
	}
	
	if(dwAfcCfg==0xFFFFFFFF) {
		switch(dwTxFifSz) {
		//AFC_HI is about ((Rx Data Fifo Size)*2/3)/64
		//AFC_LO is AFC_HI/2
		//BACK_DUR is about 5uS*(AFC_LO) rounded down
		case 0x00020000UL://13440 Rx Data Fifo Size
			dwAfcCfg=0x008C46AF;break;
		case 0x00030000UL://12480 Rx Data Fifo Size
			dwAfcCfg=0x0082419F;break;
		case 0x00040000UL://11520 Rx Data Fifo Size
			dwAfcCfg=0x00783C9F;break;
		case 0x00050000UL://10560 Rx Data Fifo Size
			//dwAfcCfg=0x006E378F;break;
			dwAfcCfg=0x006E374F;break;
		case 0x00060000UL:// 9600 Rx Data Fifo Size
			dwAfcCfg=0x0064328F;break;
		case 0x00070000UL:// 8640 Rx Data Fifo Size
			dwAfcCfg=0x005A2D7F;break;
		case 0x00080000UL:// 7680 Rx Data Fifo Size
			dwAfcCfg=0x0050287F;break;
		case 0x00090000UL:// 6720 Rx Data Fifo Size
			dwAfcCfg=0x0046236F;break;
		case 0x000A0000UL:// 5760 Rx Data Fifo Size
			dwAfcCfg=0x003C1E6F;break;
		case 0x000B0000UL:// 4800 Rx Data Fifo Size
			dwAfcCfg=0x0032195F;break;

		//AFC_HI is ~1520 bytes less than RX Data Fifo Size
		//AFC_LO is AFC_HI/2
		//BACK_DUR is about 5uS*(AFC_LO) rounded down
		case 0x000C0000UL:// 3840 Rx Data Fifo Size
			dwAfcCfg=0x0024124F;break;
		case 0x000D0000UL:// 2880 Rx Data Fifo Size
			dwAfcCfg=0x0015073F;break;
		case 0x000E0000UL:// 1920 Rx Data Fifo Size
			dwAfcCfg=0x0006032F;break;
		default:SMSC_ASSERT(FALSE);break;
		}
	}
	Lan_SetRegDW(AFC_CFG,(dwAfcCfg&0xFFFFFFF0UL));

	/*
	//make sure EEPROM has finished loading before setting GPIO_CFG
	
	dwTimeOut=1000;
	while((dwTimeOut>0)&&(Lan_GetRegDW(E2P_CMD)&E2P_CMD_EPC_BUSY_)) {
		osal_delay(5);
		dwTimeOut--;
	}
	if(dwTimeOut==0) {
		SMSC_WARNING("%s()=>Timed out waiting for EEPROM busy bit to clear\n", __FUNCTION__);
	}
	*/
	
	//Config associated pins as LEDs
	g_GpioSettingOriginal = 0x70070000UL;
	g_GpioSetting = g_GpioSettingOriginal;
	Lan_SetRegDW(GPIO_CFG,g_GpioSetting);

	pAdapter->LanInitialized=TRUE;

	return SUCCESS;
	
}


void 
Lan_EnableInterrupt(PPRIVATE_DATA pAdapter,UINT32 dwIntEnMask)
{
	UINT32 dwIntFlags=0;
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	Lan_SetBitsDW(INT_EN,dwIntEnMask);
}


void 
Lan_DisableInterrupt(PPRIVATE_DATA pAdapter,UINT32 dwIntEnMask)
{
	UINT32 dwIntFlags=0;
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	Lan_ClrBitsDW(INT_EN,dwIntEnMask);
}


void 
Lan_DisableIRQ()
{
	Lan_ClrBitsDW(INT_CFG,INT_CFG_IRQ_EN_);
}
	


void 
Lan_SetIntdeas(PPRIVATE_DATA pAdapter, UINT32 dwIntDeas)
{
	UINT32 dwIntFlags=0;
	{
		Lan_ClrBitsDW(INT_CFG,INT_CFG_INT_DEAS_);
		Lan_SetBitsDW(INT_CFG,(dwIntDeas<<24));
	}
}


void 
Lan_SignalSoftwareInterrupt(PPRIVATE_DATA pAdapter)
{
	SMSC_ASSERT(pAdapter!=NULL);
	pAdapter->SoftwareInterruptSignal=FALSE;
	Lan_EnableInterrupt(pAdapter,INT_EN_SW_INT_EN_);
}


void 
Lan_SetTDFL(PPRIVATE_DATA pAdapter, UINT8 level) 
{
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	{
		UINT32 temp=Lan_GetRegDW(FIFO_INT);
		temp&=0x00FFFFFFUL;
		temp|=((UINT32)level)<<24;
		Lan_SetRegDW(FIFO_INT,temp);
	}

}


void 
Lan_SetTSFL(PPRIVATE_DATA pAdapter, UINT8 level) 
{
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	{
		UINT32 temp=Lan_GetRegDW(FIFO_INT);
		temp&=0xFF00FFFFUL;
		temp|=((UINT32)level)<<16;
		Lan_SetRegDW(FIFO_INT,temp);
	}

}


void 
Lan_SetRSFL(PPRIVATE_DATA pAdapter, UINT8 level) 
{
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	{
		UINT32 temp=Lan_GetRegDW(FIFO_INT);
		temp&=0xFFFFFF00UL;
		temp|=((UINT32)level);
		Lan_SetRegDW(FIFO_INT,temp);
	}

}


static BOOL 
Mac_NotBusy(PPRIVATE_DATA pAdapter)
{
	int i=0;

	// wait for MAC not busy, w/ timeout
	for(i=0;i<40;i++)
	{
		if((Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)==(0UL)) {
			return TRUE;
		}
	}
	SMSC_WARNING("timeout waiting for MAC not BUSY. MAC_CSR_CMD = 0x%08lX",
		Lan_GetRegDW(MAC_CSR_CMD));
	return FALSE;
}


UINT32 
Mac_GetReg32(PPRIVATE_DATA pAdapter,UINT32 dwRegOffset)
{
	UINT32 result=0xFFFFFFFFUL;
	UINT32 dwTemp=0;
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);
	
	//wait until not busy.
	if (Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
	{
		SMSC_WARNING("%s()=>failed, MAC already busy at entry.\n", __FUNCTION__);
		goto DONE;
	}

	//send the MAC Cmd w/ offset.
	Lan_SetRegDW(MAC_CSR_CMD,
		((dwRegOffset & 0x000000FFUL) | 
		MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_));

	//Should not Read BYTE_TEST.FM-20090110
	//dwTemp=Lan_GetRegDW(BYTE_TEST);//to flush previous write
	//dwTemp=dwTemp;

	//wait for the read to happen, w/ timeout.
	if (!Mac_NotBusy(pAdapter))
	{
		SMSC_WARNING("%s()=>failed, waiting for MAC not busy after read.\n", __FUNCTION__);
		goto DONE;
	} else {
		//finally, return the read data.
		result = Lan_GetRegDW(MAC_CSR_DATA);
	}
	
DONE:
	return result;
}


void 
Mac_SetReg32(PPRIVATE_DATA pAdapter,UINT32 dwRegOffset,UINT32 dwVal)
{
	UINT32 dwTemp=0;
	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);

	if (Lan_GetRegDW(MAC_CSR_CMD) & MAC_CSR_CMD_CSR_BUSY_)
	{
		SMSC_WARNING("%s()=>failed, MAC already busy at entry.\n", __FUNCTION__);
		goto DONE;
	}

	//send the data to write.
	Lan_SetRegDW(MAC_CSR_DATA,dwVal);

	//do the actual write.
	Lan_SetRegDW(MAC_CSR_CMD,((dwRegOffset & 0x000000FFUL) | MAC_CSR_CMD_CSR_BUSY_));
	
	//dwTemp=Lan_GetRegDW(BYTE_TEST);//force flush of previous write
	//dwTemp=dwTemp;

	//wait for the write to complete, w/ timeout.
	if (!Mac_NotBusy(pAdapter))
	{
		SMSC_WARNING("%s()=>failed, waiting for MAC not busy after write", __FUNCTION__);
	}
	
DONE:
	return;
}


UINT32
Mac_GetPrint(PPRIVATE_DATA pAdapter, UINT32 off)
{
	UINT32 tmp_32 = Mac_GetReg32(pAdapter, off);

	SMSC_TRACE("=>Smsc Mac Reg 0x%02x : 0x%08x.\n", off, tmp_32);
	return tmp_32;
}


void Mac_RegTest(PPRIVATE_DATA pAdapter)
{
	UINT16 tmp_16;
	UINT32 tmp_32;
	UINT32 i;

	//Smsc io Regs test
	SMSC_TRACE("Smsc Mac Regs Write&Read Test: \n");

	for(i = 1; i < 0xf; i += 1)
	{
		SMSC_TRACE("=>Smsc Mac Reg 0x%02x : 0x%08x", i, Mac_GetReg32(pAdapter,i));
		Mac_SetReg32(pAdapter,i, 0x00000000);
		SMSC_TRACE("=>=======>after write 0 : 0x%02x : 0x%08x", i, Mac_GetReg32(pAdapter,i));
		Mac_SetReg32(pAdapter,i, 0xffffffff);
		SMSC_TRACE("=>=======>after write 1 : 0x%02x : 0x%08x.\n", i, Mac_GetReg32(pAdapter,i));
	}

	//asm("sdbbp");
	SDBBP();
}


void 
Rx_ReceiverOn(PPRIVATE_DATA pAdapter)
{
	UINT32 dwIntFlags=0;

	if(pAdapter->RxOffCount>0) 
	{
		pAdapter->RxOffCount--;
		if(pAdapter->RxOffCount==0) 
		{
			Lan_MutexLock(pAdapter->MacPhyLock);
			UINT32 dwMacCr=Mac_GetReg32(pAdapter,MAC_CR);

			//Mac working mode=>Promiscuous.
			dwMacCr &= 0xFFF0FFFF;
			dwMacCr |= MAC_CR_PRMS_;
			
			if(dwMacCr&MAC_CR_RXEN_) 
			{
				SMSC_WARNING("%()=>Receiver is already on.\n",__FUNCTION__);
			}
			dwMacCr|=MAC_CR_RXEN_;
			Mac_SetReg32(pAdapter,MAC_CR,dwMacCr);
			//SET_GPIO(GP_RX);
			Lan_MutexUnlock(pAdapter->MacPhyLock);
		}
	} 
	else 
	{
		SMSC_WARNING("%()=>RxOffCount<=0.\n",__FUNCTION__);
		SMSC_ASSERT(FALSE);
	}

}


//Get Rx Status info from Rx Status FIFO. 
static UINT32 
Rx_PopRxStatus(PPRIVATE_DATA pAdapter)
{
	
	UINT32 result;
	int i=0;
		
	result=Lan_GetRegDW(RX_FIFO_INF);
	
	//Check If Rx Status Fifo is Available.
	if(result&0x00FF0000UL)
		result=Lan_GetRegDW(RX_STATUS_FIFO);
	else 
		result=0;

	return result;
}


//Record Rx Error status.
void 
Rx_CountErrors(PPRIVATE_DATA pAdapter,UINT32 dwRxStatus) 
{
	BOOL crcError=FALSE;
	
	//bit15(Error Status)
	if(dwRxStatus&0x00008000UL) {
		pAdapter->stats.rx_errors++;
		//bit1(CRC Error)
		if(dwRxStatus&0x00000002UL) {
			pAdapter->stats.rx_crc_errors++;
			crcError=TRUE;
		}
	}
	if(!crcError) {
		//bit5(Frame Type) bit12(Length Error)
		if((dwRxStatus&0x00001020UL)==0x00001020UL) {
			pAdapter->stats.rx_length_errors++;
		}
		//bit10(Multicast Frame)
		if(dwRxStatus&RX_STS_MCAST_) {
			pAdapter->stats.multicast++;
		}
	}
}


void 
Rx_FastForward(PPRIVATE_DATA pAdapter,UINT32 dwDwordCount)
{
	
	if(dwDwordCount>=4)
	{
		UINT32 dwTimeOut=500;
		Lan_SetRegDW(RX_DP_CTRL,(dwDwordCount|RX_DP_CTRL_FFWD_BUSY_));
		while((dwTimeOut)&&(Lan_GetRegDW(RX_DP_CTRL)&RX_DP_CTRL_FFWD_BUSY_))
		{
			osal_delay(1);
			dwTimeOut--;
		}
		if(dwTimeOut==0) 
		{
			SMSC_WARNING("%s()=>timed out waiting for RX FFWD to finish, RX_DP_CTRL=0x%08lX.\n",
				__FUNCTION__, Lan_GetRegDW(RX_DP_CTRL));
		}
	} 
	else 
	{
		while(dwDwordCount) {
			UINT32 dwTemp=Lan_GetRegDW(RX_DATA_FIFO);
			dwTemp=dwTemp;
			dwDwordCount--;
		}
	}
}


void 
Rx_ReceivePackets(PPRIVATE_DATA pAdapter)
{
	UINT32 dwRxStatus=0;
	UINT32 PacketLength;
	int cnt =0;

	Lan_SetRegDW(RX_CFG,RX_CFG_RXDOFF_2_);
	
	cnt =0;			
	while((dwRxStatus=Rx_PopRxStatus(pAdapter))!=0)
	{
		UINT32 dwPacketLength=((dwRxStatus&0x3FFF0000UL)>>16);

		//SMSC_TRACE("%s()=>PacketLength(%d)", __FUNCTION__, (UINT32) dwPacketLength);
		//SMSC_TRACE("RxStatus(0x%08lx).\n", (UINT32) dwRxStatus);
			
		Rx_CountErrors(pAdapter,dwRxStatus);

		//If No Rx Errors.
		if((dwRxStatus&RX_STS_ES_)==0)
	 	{
			pAdapter->stats.rx_packets++;

			//Rx Checksum(2) FCS(4)
			if (pAdapter->UseRxCsum)
			{
				PacketLength = dwPacketLength-4-2;
			}
			else
			{	
				PacketLength = dwPacketLength-4;
			}

			pAdapter->stats.rx_bytes+=PacketLength;

			//Lan_MutexLock(pAdapter->TransMutex);
			//Rx Data Offset(2) Padding(3) 
			smsc_ReadDataFifo(pAdapter->TransferMode, pAdapter->RxBuffer, (dwPacketLength+2+3)>>2);
			//Lan_MutexUnlock(pAdapter->TransMutex);
				
			//Lan_PrintBuf((UINT8 *)(pAdapter->RxBuffer)+2, PacketLength);
				
			if (pAdapter->dev->callback)
			{
				struct net_pkt_t cur_rx_pkt;
					
				cur_rx_pkt.buffer = (UINT8 *)(pAdapter->RxBuffer)+2;
				cur_rx_pkt.length = PacketLength;
			    pAdapter->dev->callback(pAdapter->dev, NET_RECV_PKT, (UINT32)&cur_rx_pkt);
			}
				
			cnt ++;
			if(cnt > SMSC_RXPKTS_PERTIME)
				break;

		}
		else //Rx Error happens
		{
			SMSC_WARNING("%s()=>Rx Error happens.", __FUNCTION__);
			SMSC_TRACE("RxStatus(0x%08lx).\n", (UINT32) dwRxStatus);
			//if we get here then the packet is to be read
			//	out of the fifo and discarded
			//Rx Data Offset(2) Padding(3) 
			dwPacketLength+=(2+3);
			dwPacketLength>>=2;
			Rx_FastForward(pAdapter,dwPacketLength);
		}
	}

	//Clear Rx Int Status.
	Lan_SetRegDW(INT_STS,INT_STS_RSFL_);
}


void Rx_Interrupt(PPRIVATE_DATA pAdapter, UINT32 dwIntSts)
{
	//pAdapter->LastReasonForReleasingCPU=0;
	//bit14=>Rx Err Int.
	if(dwIntSts&INT_STS_RXE_) 
	{
		SMSC_TRACE("%s()=>RXE signalled.\n",__FUNCTION__);
		pAdapter->stats.rx_errors++;
		Lan_SetRegDW(INT_STS,INT_STS_RXE_);
	}

	//bit23=>Rx Drop Frame Halfway Int.
	if(dwIntSts&INT_STS_RXDFH_INT_) 
	{
		SMSC_TRACE("%s()=>RXDFH signalled.\n",__FUNCTION__);
		pAdapter->stats.rx_dropped+=Lan_GetRegDW(RX_DROP);
		Lan_SetRegDW(INT_STS,INT_STS_RXDFH_INT_);
	}

	//bit6=>Rx Drop Frame Int.
	if(dwIntSts&(INT_STS_RDFO_)) 
	{
		SMSC_TRACE("%s()=>RXDF signalled.\n",__FUNCTION__);
		Lan_SetRegDW(INT_STS,INT_STS_RDFO_);
	}

	//bit3=>Rx Status Fifo Level Int.	
	if(dwIntSts&INT_STS_RSFL_)
	{
		Rx_ReceivePackets(pAdapter);
	}
	
}


/*FM-20091214
Added for Rx flow control.
*/
BOOL Rx_StopInterrupt(PPRIVATE_DATA privateData, DWORD dwIntSts)
{
	if(dwIntSts&INT_STS_RXSTOP_INT_) 
	{
		SMSC_TRACE("Rx Stopped...\n");
		Lan_SetRegDW(INT_STS,INT_STS_RXSTOP_INT_);
		Lan_DisableInterrupt(privateData,INT_EN_RXSTOP_INT_EN_);
	}
}


//Remove Rx FC.FM-20091216
void 
Rx_Initialize(PPRIVATE_DATA pAdapter)
{
	if(int_deas!=0xFFFFFFFFUL)
		Lan_SetIntdeas(pAdapter,int_deas);

	if(0)//Set vlan tag
	{
		UINT32 dwIntFlags=0;
		Lan_MutexLock(pAdapter->MacPhyLock);
		//Mac_SetReg32(pAdapter,VLAN1,ETH_P_8021Q);
		Lan_MutexUnlock(pAdapter->MacPhyLock);
		//pAdapter->RxVLanPkt=TRUE;		
	}

	//Rx checksum.
	if (pAdapter->UseRxCsum)
	{
		UINT32 dwIntFlags=0;
		Lan_MutexLock(pAdapter->MacPhyLock);
		
		UINT32 dwCoeCr=Mac_GetReg32(pAdapter,COE_CR);		
		//dwCoeCr|=(RX_COE_EN |  RX_COE_MODE);
		//do not care VLAN tag or SNAP header.FM-20081231
		dwCoeCr|=(RX_COE_EN);
		Mac_SetReg32(pAdapter,COE_CR,dwCoeCr);
		Lan_MutexUnlock(pAdapter->MacPhyLock);
	}

	//initially the receiver is off
	//a following link up detection will turn the receiver on
	pAdapter->RxOffCount=1;

	Lan_SetRegDW(RX_CFG,RX_CFG_RXDOFF_2_);
	Rx_ReceiverOn(pAdapter);
	
	//Lan_SetRDFL(pAdapter,0x01);
	Lan_SetRSFL(pAdapter,0x00);
	pAdapter->RxInterrupts=INT_EN_RSFL_EN_;	//rx status fifo level en
	pAdapter->RxInterrupts|=INT_EN_RXE_EN_;	//rx err int en
	pAdapter->RxInterrupts|=INT_EN_RDFO_EN_;	//rx data fifo overflow(RXDF) en
	pAdapter->RxInterrupts|=INT_EN_RXDFH_INT_EN_;//RX Drop Fram Halfway en

	Lan_EnableInterrupt(pAdapter,pAdapter->RxInterrupts);
}


void 
Tx_Initialize(PPRIVATE_DATA pAdapter)
{
	UINT32 dwRegVal=0;

	dwRegVal=Lan_GetRegDW(HW_CFG);
	//HW_CFG=>bit20(Must Be One) bit19:16(TX FIFO Size)
	dwRegVal&=(HW_CFG_TX_FIF_SZ_|0x00000FFFUL);
	dwRegVal|=HW_CFG_SF_;
	Lan_SetRegDW(HW_CFG,dwRegVal);

	if(pAdapter->UseTxCsum)
	//Set TX COE
 	{
		UINT32 dwIntFlags=0;
		Lan_MutexLock(pAdapter->MacPhyLock);
		
		UINT32 dwCoeCr=Mac_GetReg32(pAdapter,COE_CR);
		
		dwCoeCr|=(TX_COE_EN);
		Mac_SetReg32(pAdapter,COE_CR,dwCoeCr);
		
		//SMSC_TRACE("%s()=>COE_CR = 0x%08lx\n", __FUNCTION__, Mac_GetReg32(pAdapter,COE_CR));
		Lan_MutexUnlock(pAdapter->MacPhyLock);	
	}	
	
	//Set TX Data Available Level to Highest level.
	Lan_SetTDFL(pAdapter,0xFF);
	Lan_EnableInterrupt(pAdapter,INT_EN_TDFA_EN_);

	{//En Tx
		UINT32 dwIntFlags=0;
		Lan_MutexLock(pAdapter->MacPhyLock);
		
		UINT32 dwMacCr=Mac_GetReg32(pAdapter,MAC_CR);
		//dwMacCr|=(MAC_CR_TXEN_|MAC_CR_HBDIS_);
		dwMacCr|=MAC_CR_TXEN_;
		Mac_SetReg32(pAdapter,MAC_CR,dwMacCr);
		Lan_SetRegDW(TX_CFG,TX_CFG_TX_ON_);
		
		Lan_MutexUnlock(pAdapter->MacPhyLock);	
	}

}


static UINT32 
Tx_GetStatusCount(PPRIVATE_DATA pAdapter)
{
	UINT32 result=0;

	result=Lan_GetRegDW(TX_FIFO_INF);

	result&=TX_FIFO_INF_TSUSED_;
	result>>=16;

	return result;
}


static UINT32 
Tx_Complete(PPRIVATE_DATA pAdapter)
{
	UINT32 result=0;

	result=Lan_GetRegDW(TX_FIFO_INF);
	
	result&=TX_FIFO_INF_TSUSED_;
	if(result!=0x00000000UL) {
		result=Lan_GetRegDW(TX_STATUS_FIFO);
	} else {
		result=0;
	}

	return result;
}


int 
Tx_UpdateCounters(PPRIVATE_DATA pAdapter)
{
	int re = 0;
	UINT32 dwTxStatus=0;

	while((dwTxStatus=Tx_Complete(pAdapter))!=0)
	{
		if(dwTxStatus&0x80000000UL) 
		{
			SMSC_WARNING("Tx_UpdateCounters()=>Packet tag reserved bit is high.\n");
			pAdapter->stats.tx_errors++; re = -1;
		} 
		else if(dwTxStatus&0x00007080UL) 
		{
			SMSC_WARNING("Tx_UpdateCounters()=>Tx Status reserved bits are high.\n");
			pAdapter->stats.tx_errors++; re = -1;
		} 
		else 
		{
			if(dwTxStatus&0x00008000UL) 
			{
				//not care No Carrier Errors.
				if(!(dwTxStatus&0x00000400UL))
				{
					SMSC_WARNING("Tx_UpdateCounters()=>Tx errors(0x%08x).\n", dwTxStatus);
					pAdapter->stats.tx_errors++; re = -1;
				}
			} 
			else 
			{
				pAdapter->stats.tx_packets++;
				pAdapter->stats.tx_bytes+=(dwTxStatus>>16);
			}
			
			if(dwTxStatus&0x00000100UL) 
			{
				pAdapter->stats.collisions+=16;
				pAdapter->stats.tx_aborted_errors+=1;
			}
			else 
			{
				pAdapter->stats.collisions+=
					((dwTxStatus>>3)&0xFUL);
			}
			
			if(dwTxStatus&0x00000800UL) 
			{
				pAdapter->stats.tx_carrier_errors+=1;
			}
			
			if(dwTxStatus&0x00000200UL) 
			{
				pAdapter->stats.collisions++;
				pAdapter->stats.tx_aborted_errors++;
			}
		}
	}

	return re;

}


//it's maybe ugly.FM-20090102
int
Tx_SendBuf(PPRIVATE_DATA pAdapter, void *buf, UINT16 len)
{
	UINT32 fifo_len, data_off = 0;
	int re = 0;
	
#ifndef SMSC_UP_BUS	
	//Enter Mutex
	if(smsc_mutex_id.lock)
	{
		smsc_mutex_id.lock();
		//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
		HAL_GPIO_BIT_SET(SMSC_CS, 0);	
	}
#endif //SMSC_UP_BUS

	if((len & 0x7ff) < 14 || (len & 0x7ff) > 1514)
	{
		SMSC_WARNING("%s()=>pkt len err(%d).\n",__FUNCTION__, len);
		re = -1;
		goto Tx_Err;
	}

	data_off = ((UINT32)(buf) & 0x03UL);
	fifo_len = (len + data_off + 3)>>2;
	
	smsc_WriteDataFifo(pAdapter, buf, len);
	
	if(Tx_GetStatusCount(pAdapter)>=30)
	{
		Tx_UpdateCounters(pAdapter);
	}

Tx_Err:	
	
#ifndef SMSC_UP_BUS	
	//Exit Mutex
	if(smsc_mutex_id.unlock)
	{
		//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
		HAL_GPIO_BIT_SET(SMSC_CS, 1);
		smsc_mutex_id.unlock();
	}
#endif //SMSC_UP_BUS
	
	return re;
}


BOOL
Tx_StartInterrupt(PPRIVATE_DATA pAdapter, UINT32 dwIntSts)
{
	if(dwIntSts&INT_STS_TDFA_) 
	{
		//SMSC_TRACE("Tx Started...\n");
		Lan_SetTDFL(pAdapter,0xFF);
		Lan_SetRegDW(INT_STS,INT_STS_TDFA_);
	}
}


UINT16 
 Phy_GetReg16(PPRIVATE_DATA pAdapter,UINT32 dwRegIndex)
{
	UINT32 dwAddr=0;
	int i=0;
	UINT16 result=0xFFFFU;

	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);

	// confirm MII not busy
	if ((Mac_GetReg32(pAdapter, MII_ACC) & MII_ACC_MII_BUSY_) != 0UL)
	{
		SMSC_WARNING("%s()=>MII is busy???\n", __FUNCTION__);
		result=0;
		goto DONE;
	}

	// set the address, index & direction (read from PHY)
	dwAddr = ((pAdapter->PhyAddr&0x1FUL)<<11) | ((dwRegIndex & 0x1FUL)<<6);
	Mac_SetReg32(pAdapter, MII_ACC, dwAddr);

	//Mac_GetPrint(pAdapter, MII_ACC);

	// wait for read to complete w/ timeout
	for(i=0;i<100;i++) {
		// see if MII is finished yet
		if ((Mac_GetReg32(pAdapter, MII_ACC) & MII_ACC_MII_BUSY_) == 0UL)
		{
			// get the read data from the MAC & return i
			result=((WORD)Mac_GetReg32(pAdapter, MII_DATA));
			goto DONE;
		}
	}
	SMSC_WARNING("%s()=>timeout waiting for MII write to finish.\n", __FUNCTION__);

DONE:
	return result;
}

void Phy_SetReg16(PPRIVATE_DATA pAdapter,UINT32 dwRegIndex,UINT16 wVal)
{
	UINT32 dwAddr=0;
	int i=0;

	SMSC_ASSERT(pAdapter!=NULL);
	SMSC_ASSERT(pAdapter->LanInitialized==TRUE);

	if(dwRegIndex==0) {
		if((wVal&0x1200)==0x1200) {
			pAdapter->LastADVatRestart=pAdapter->wLastADV;
		}
	}
	if(dwRegIndex==4) {
		pAdapter->wLastADV=wVal;
	}

	// confirm MII not busy
	if ((Mac_GetReg32(pAdapter, MII_ACC) & MII_ACC_MII_BUSY_) != 0UL)
	{
		SMSC_WARNING("%s()=>MII is busy???\n", __FUNCTION__);
		goto DONE;
	}

	// put the data to write in the MAC
	Mac_SetReg32(pAdapter, MII_DATA, (UINT32)wVal);

	// set the address, index & direction (write to PHY)
	dwAddr = ((pAdapter->PhyAddr&0x1FUL)<<11) | ((dwRegIndex & 0x1FUL)<<6) | MII_ACC_MII_WRITE_;
	Mac_SetReg32(pAdapter, MII_ACC, dwAddr);

	// wait for write to complete w/ timeout
	for(i=0;i<100;i++) {
		// see if MII is finished yet
		if ((Mac_GetReg32(pAdapter, MII_ACC) & MII_ACC_MII_BUSY_) == 0UL)
		{
			goto DONE;
		}
	}
	SMSC_WARNING("%s()=>timeout waiting for MII write to finish.\n", __FUNCTION__);
DONE:
	return;
}


void
Phy_RegTest(PPRIVATE_DATA pAdapter)
{
	UINT16 tmp_16;
	UINT32 i;

	//Smsc io Regs test
	SMSC_TRACE("Smsc Phy Regs Write&Read Test: \n");

	for(i = 0; i < 31; i += 1)
	{
		if(1)
			SMSC_TRACE("=>Smsc Phy Reg %d: 0x%04x.\n", i, Phy_GetReg16(pAdapter,i));
		else
		{
			SMSC_TRACE("=>Smsc Phy Reg %d: 0x%04x", i, Phy_GetReg16(pAdapter,i));
			Phy_SetReg16(pAdapter,i, 0x0000);
			SMSC_TRACE("=>=======>after write 0: 0x%04x", Phy_GetReg16(pAdapter,i));
			Phy_SetReg16(pAdapter,i, 0xffff);
			SMSC_TRACE("=>=======>after write 1: 0x%04x.\n", Phy_GetReg16(pAdapter,i));
		}
	}

	//asm("sdbbp");
	SDBBP();
}


void 
Phy_GetLinkMode(PPRIVATE_DATA pAdapter)
	
{
	UINT32 result=LINK_OFF;
	UINT16 wRegVal=0;

	UINT16 wRegBSR=Phy_GetReg16(pAdapter,PHY_BSR);
	pAdapter->LinkSettings=LINK_OFF;

	//Check if Link Status is UP.
	if(wRegBSR&PHY_BSR_LINK_STATUS_) 
	{
		wRegVal=Phy_GetReg16(pAdapter,PHY_BCR);
		
		//Check if Auto-Neg is Enable.
		if(wRegVal&PHY_BCR_AUTO_NEG_ENABLE_) 
		{
			UINT32 linkSettings=LINK_AUTO_NEGOTIATE;
			UINT16 wRegADV=pAdapter->LastADVatRestart;
//					Phy_GetRegW(
//						pAdapter,
//						PHY_ANEG_ADV,keyCode);
			UINT16 wRegLPA=Phy_GetReg16(pAdapter,PHY_ANEG_LPA);
			if(wRegADV&PHY_ANEG_ADV_ASYMP_) {
				linkSettings|=LINK_ASYMMETRIC_PAUSE;//one-direction Pause Fame
			}
			if(wRegADV&PHY_ANEG_ADV_SYMP_) {
				linkSettings|=LINK_SYMMETRIC_PAUSE;//both-direction Pause Fame
			}
			if(wRegADV&PHY_ANEG_LPA_100FDX_) {
				linkSettings|=LINK_SPEED_100FD;
			}
			if(wRegADV&PHY_ANEG_LPA_100HDX_) {
				linkSettings|=LINK_SPEED_100HD;
			}
			if(wRegADV&PHY_ANEG_LPA_10FDX_) {
				linkSettings|=LINK_SPEED_10FD;
			}
			if(wRegADV&PHY_ANEG_LPA_10HDX_) {
				linkSettings|=LINK_SPEED_10HD;
			}
			pAdapter->LinkSettings=linkSettings;
			wRegLPA&=wRegADV;
			if(wRegLPA&PHY_ANEG_LPA_100FDX_) {
				result=LINK_SPEED_100FD;
			} else if(wRegLPA&PHY_ANEG_LPA_100HDX_) {
				result=LINK_SPEED_100HD;
			} else if(wRegLPA&PHY_ANEG_LPA_10FDX_) {
				result=LINK_SPEED_10FD;
			} else if(wRegLPA&PHY_ANEG_LPA_10HDX_) {
				result=LINK_SPEED_10HD;
			}
		} else {
			if(wRegVal&PHY_BCR_SPEED_SELECT_) {
				if(wRegVal&PHY_BCR_DUPLEX_MODE_) {
					pAdapter->LinkSettings=result=LINK_SPEED_100FD;
				} else {
					pAdapter->LinkSettings=result=LINK_SPEED_100HD;
				}
			} else {
				if(wRegVal&PHY_BCR_DUPLEX_MODE_) {
					pAdapter->LinkSettings=result=LINK_SPEED_10FD;
				} else {
					pAdapter->LinkSettings=result=LINK_SPEED_10HD;
				}
			}
		}
	}
	pAdapter->LinkSpeed=result;
}


/*
FM-20090105.
Step 1=>Check Link Mode & Set Advertisement.(PHY_ANEG_ADV)
Step 2=>Start Auto-Negotiation.(PHY_BCR).
*/
void 
Phy_SetLink(PPRIVATE_DATA pAdapter) 
{
	UINT32 dwIntFlags=0;
	UINT32 dwLinkRequest = pAdapter->LinkMode;
	UINT16 wTemp=0;
	
	Lan_MutexLock(pAdapter->MacPhyLock);
	
	if(dwLinkRequest&LINK_AUTO_NEGOTIATE) 
	{
		//Check Link Mode & Set Advertisement.
		wTemp=Phy_GetReg16(pAdapter,PHY_ANEG_ADV);
		wTemp&=~PHY_ANEG_ADV_PAUSE_;
		if(dwLinkRequest&LINK_ASYMMETRIC_PAUSE) {
			wTemp|=PHY_ANEG_ADV_ASYMP_;
		} 
		if(dwLinkRequest&LINK_SYMMETRIC_PAUSE) {
			wTemp|=PHY_ANEG_ADV_SYMP_;
		}
		wTemp&=~PHY_ANEG_ADV_SPEED_;
		if(dwLinkRequest&LINK_SPEED_10HD) {
			wTemp|=PHY_ANEG_ADV_10H_;
		}
		if(dwLinkRequest&LINK_SPEED_10FD) {
			wTemp|=PHY_ANEG_ADV_10F_;
		}
		if(dwLinkRequest&LINK_SPEED_100HD) {
			wTemp|=PHY_ANEG_ADV_100H_;
		}
		if(dwLinkRequest&LINK_SPEED_100FD) {
			wTemp|=PHY_ANEG_ADV_100F_;
		}
		Phy_SetReg16(pAdapter,PHY_ANEG_ADV,wTemp);

		//Start Auto-Negotiation
		Phy_SetReg16(pAdapter,PHY_BCR,
			PHY_BCR_AUTO_NEG_ENABLE_|PHY_BCR_RESTART_AUTO_NEG_);
	}
	else //if(dwLinkRequest&LINK_AUTO_NEGOTIATE) 
	{
		if(dwLinkRequest&(LINK_SPEED_100FD)) {
			dwLinkRequest=LINK_SPEED_100FD;
		} else if(dwLinkRequest&(LINK_SPEED_100HD)) {
			dwLinkRequest=LINK_SPEED_100HD;
		} else if(dwLinkRequest&(LINK_SPEED_10FD)) {
			dwLinkRequest=LINK_SPEED_10FD;
		} else if(dwLinkRequest&(LINK_SPEED_10HD)) {
			dwLinkRequest=LINK_SPEED_10HD;
		}
		if(dwLinkRequest&(LINK_SPEED_10FD|LINK_SPEED_100FD)) {
			wTemp|=PHY_BCR_DUPLEX_MODE_;
		}
		if(dwLinkRequest&(LINK_SPEED_100HD|LINK_SPEED_100FD)) {
			wTemp|=PHY_BCR_SPEED_SELECT_;
		}
		Phy_SetReg16(pAdapter,PHY_BCR,wTemp);
	}
	Lan_MutexUnlock(pAdapter->MacPhyLock);
}


/*
Set AutoMdix Mode.
	0: Override Strap, Disable AutoMdix, Using Straight Cable
	1: Override Strap, Disable AutoMdix, Using CrossOver Cable
	2: Override Strap, Enable AutoMdix
	>=3 or No Keyword: AutoMdix controlled by Strap
*/
void 
Phy_SetAutoMdixSts(PPRIVATE_DATA pAdapter)
{
	UINT16 wAutoMdixSts = pAdapter->AutoMdix;
	UINT16 SpecialCtrlSts=0;
	UINT32 dwIntFlags=0;

	//AutoMdix controlled by Strap(pin73)
	if (wAutoMdixSts > 2)
	{
		Lan_MutexLock(pAdapter->MacPhyLock);
		//Phy_RegTest(pAdapter);
		SpecialCtrlSts=Phy_GetReg16(pAdapter, SPECIAL_CTRL_STS);
		SpecialCtrlSts = (SpecialCtrlSts&0x1FFF);
		Phy_SetReg16(pAdapter, SPECIAL_CTRL_STS,SpecialCtrlSts);
		Lan_MutexUnlock(pAdapter->MacPhyLock);

		if (Lan_GetRegDW(HW_CFG) & HW_CFG_AMDIX_EN_STRAP_STS_) 
			SMSC_TRACE("%s()=>Auto-MDIX Enable by default!!!\n", __FUNCTION__);
		else 
			SMSC_TRACE("%s()=>Auto-MDIX Disable by default!!!\n", __FUNCTION__);
       }
	else 
	{
		Lan_MutexLock(pAdapter->MacPhyLock);
		SpecialCtrlSts=Phy_GetReg16(pAdapter, SPECIAL_CTRL_STS);
		//bit15(Override AMDIX Strap) bit14(AutoMdix En) bit13(AutoMdix State)
		SpecialCtrlSts = (((wAutoMdixSts+4) << 13) | (SpecialCtrlSts&0x1FFF));
		Phy_SetReg16(pAdapter, SPECIAL_CTRL_STS,SpecialCtrlSts);
		Lan_MutexUnlock(pAdapter->MacPhyLock);	

		if (wAutoMdixSts & AMDIX_ENABLE) 
			SMSC_TRACE("%()=>Override Strap, Enable Auto-MDIX.\n", __FUNCTION__);
		else if (wAutoMdixSts & AMDIX_DISABLE_CROSSOVER) 
			SMSC_TRACE("%()=>Override Strap, Disable Auto-MDIX, CrossOver Cable.\n", __FUNCTION__);		
		else 
			SMSC_TRACE("%()=>Override Strap, Disable Auto-MDIX, Straight Cable.\n", __FUNCTION__);		
	}

}


/*
Step 1=>Update Link Status.
Step 2=>If it changed, Update Mac working mode.
Step 3=>Flow Control.(If it Needs)
*/
void 
Phy_UpdateLinkMode(PPRIVATE_DATA pAdapter)
{
	UINT32 dwOldLinkSpeed=pAdapter->LinkSpeed;
	UINT32 dwIntFlags=0;
	
	Lan_MutexLock(pAdapter->MacPhyLock);

	Phy_GetLinkMode(pAdapter);

	//If Link Status Changed.
	if(dwOldLinkSpeed!=(pAdapter->LinkSpeed)) 
	{
		//Link Status is ON.
		if(pAdapter->LinkSpeed!=LINK_OFF) 
		{
			UINT32 dwRegVal=0;
			
			switch(pAdapter->LinkSpeed) 
			{
				case LINK_SPEED_10HD:
					SMSC_TRACE("%s()=>Link is now UP at 10Mbps HD.\n",__FUNCTION__);
					break;
				case LINK_SPEED_10FD:
					SMSC_TRACE("%s()=>Link is now UP at 10Mbps FD.\n",__FUNCTION__);
					break;
				case LINK_SPEED_100HD:
					SMSC_TRACE("%s()=>Link is now UP at 100Mbps HD.\n",__FUNCTION__);
					break;
				case LINK_SPEED_100FD:
					SMSC_TRACE("%s()=>Link is now UP at 100Mbps FD.\n",__FUNCTION__);
					break;
				default:
					SMSC_WARNING("%s()=>Link is now UP at Unknown Link Speed, LinkSpeed=0x%08lX.\n",
						__FUNCTION__, pAdapter->LinkSpeed);
					break;
			}
		
			dwRegVal=Mac_GetReg32(pAdapter,MAC_CR);
			dwRegVal&=~(MAC_CR_FDPX_|MAC_CR_RCVOWN_);
			
			switch(pAdapter->LinkSpeed) 
			{
				case LINK_SPEED_10HD:
				case LINK_SPEED_100HD:
					dwRegVal|=MAC_CR_RCVOWN_;
					break;
				case LINK_SPEED_10FD:
				case LINK_SPEED_100FD:
					dwRegVal|=MAC_CR_FDPX_;
					break;
				default:break;//make lint happy
			}

			Mac_SetReg32(pAdapter,MAC_CR,dwRegVal);

			//if(pAdapter->LinkSettings&LINK_AUTO_NEGOTIATE)
			if(0) //Just Dis FC.FM-20090106. 
			{
				UINT16 linkPartner=0;
				UINT16 localLink=0;
				localLink=Phy_GetReg16(pAdapter,4);
				linkPartner=Phy_GetReg16(pAdapter,5);
				switch(pAdapter->LinkSpeed) 
				{
					case LINK_SPEED_10FD:
					case LINK_SPEED_100FD:
						//Check if Smmetric PAUSE bit has been set by both sides.
						if(((localLink&linkPartner)&((UINT16)0x0400U)) != ((UINT16)0U)) 
						{
							//Enable PAUSE receive and transmit
							//FLOW=>bit2(Flow Control Enable) bit31:16(Pause Time)
							Mac_SetReg32(pAdapter,FLOW,0xFFFF0002UL);
							Lan_SetBitsDW(AFC_CFG,(pAdapter->AfcConfig&0x0000000FUL));
						} 
						else if(((localLink&((UINT16)0x0C00U))==((UINT16)0x0C00U)) &&
								((linkPartner&((UINT16)0x0C00U))==((UINT16)0x0800U)))
						{
							//Enable PAUSE receive, disable PAUSE transmit
							Mac_SetReg32(pAdapter,FLOW,0xFFFF0002UL);
							Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
						} 
						else 
						{
							//Disable PAUSE receive and transmit
							Mac_SetReg32(pAdapter,FLOW,0UL);
							Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
						}
						break;
					case LINK_SPEED_10HD:
					case LINK_SPEED_100HD:
						Mac_SetReg32(pAdapter,FLOW,0UL);
						Lan_SetBitsDW(AFC_CFG,0x0000000FUL);
						break;
					default:break;//make lint happy
				}
				SMSC_TRACE("%s()=>LAN9220: %s,%s,%s,%s,%s,%s.\n",__FUNCTION__, 
					(localLink&PHY_ANEG_ADV_ASYMP_)?"ASYMP":"     ",
					(localLink&PHY_ANEG_ADV_SYMP_)?"SYMP ":"     ",
					(localLink&PHY_ANEG_ADV_100F_)?"100FD":"     ",
					(localLink&PHY_ANEG_ADV_100H_)?"100HD":"     ",
					(localLink&PHY_ANEG_ADV_10F_)?"10FD ":"     ",
					(localLink&PHY_ANEG_ADV_10H_)?"10HD ":"     ");
	
				SMSC_TRACE("%s()=>Partner: %s,%s,%s,%s,%s,%s.\n",__FUNCTION__, 
					(linkPartner&PHY_ANEG_LPA_ASYMP_)?"ASYMP":"     ",
					(linkPartner&PHY_ANEG_LPA_SYMP_)?"SYMP ":"     ",
					(linkPartner&PHY_ANEG_LPA_100FDX_)?"100FD":"     ",
					(linkPartner&PHY_ANEG_LPA_100HDX_)?"100HD":"     ",
					(linkPartner&PHY_ANEG_LPA_10FDX_)?"10FD ":"     ",
					(linkPartner&PHY_ANEG_LPA_10HDX_)?"10HD ":"     ");
			} 
			else 
			{
				switch(pAdapter->LinkSpeed) 
				{
					case LINK_SPEED_10HD:
					case LINK_SPEED_100HD:
						Mac_SetReg32(pAdapter,FLOW,0x0UL);
						Lan_SetBitsDW(AFC_CFG,0x0000000FUL);
						break;
					default:
						Mac_SetReg32(pAdapter,FLOW,0x0UL);
						Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);
						break;
				}
			}
			
		} 
		//Link Status is DOWN.
		else 
		{
			SMSC_TRACE("%s()=>Link is now DOWN.\n", __FUNCTION__);
			//Turn off netif, dis Flow Control, dis Auto Flow Control.
			Mac_SetReg32(pAdapter,FLOW,0UL);
			Lan_ClrBitsDW(AFC_CFG,0x0000000FUL);

			// Check global setting that LED1 usage is 10/100 indicator
//			g_GpioSetting = Lan_GetRegDW(GPIO_CFG);
			if (g_GpioSetting & GPIO_CFG_LED1_EN_)
			{
				//Force 10/100 LED off, after saving orginal GPIO configuration
				g_GpioSettingOriginal = g_GpioSetting;

				g_GpioSetting &= ~GPIO_CFG_LED1_EN_;
				g_GpioSetting |=
					(GPIO_CFG_GPIOBUF0_|GPIO_CFG_GPIODIR0_|GPIO_CFG_GPIOD0_);
				Lan_SetRegDW(GPIO_CFG,g_GpioSetting);
			}

		}
	}
	
	Lan_MutexUnlock(pAdapter->MacPhyLock);
}


void Phy_CheckLink(UINT32 ptr)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)ptr;
	if(pAdapter==NULL) {
		SMSC_WARNING("%s()=>(ptr==0).\n",__FUNCTION__);
		return;
	}
	
	//must call this twice
	Phy_UpdateLinkMode(pAdapter);
	osal_task_sleep(100);//need to Check more.FM-20090112 
	Phy_UpdateLinkMode(pAdapter);
	
	osal_task_sleep(900);

}

void Phy_Interrupt(PPRIVATE_DATA pAdapter)
{
	UINT16 sts;

	Lan_MutexLock(pAdapter->MacPhyLock);

	sts = Phy_GetReg16(pAdapter, PHY_INT_SRC);
	//SMSC_TRACE("%s()=>Phy Int Src(0x%04x).\n",__FUNCTION__, sts);
	
	if((sts & PHY_INT_MASK_ENERGY_ON_) &&(sts & PHY_INT_MASK_ANEG_COMP_))
	{
		SMSC_TRACE("%s()=>Link is OKay(0x%04x).\n",__FUNCTION__, sts);
		pAdapter->LinkStatus = TRUE;
	}
	
	if((sts & PHY_INT_MASK_ANEG_COMP_) == 0)
	{
		SMSC_TRACE("%s()=>Link is Down(0x%04x).\n",__FUNCTION__, sts);
		pAdapter->LinkStatus = FALSE;
	}		


	Lan_MutexUnlock(pAdapter->MacPhyLock);
}


/*
Step 1=>Set AutoMdix Mode.
Step 2=>Reset Phy.
Step 3=>Auto Negotiation.
*/
RET_CODE
Phy_Initialize(PPRIVATE_DATA pAdapter)
{
	RET_CODE result=SUCCESS;
	UINT32 dwTemp=0;
	UINT16 wTemp=0;
	UINT32 dwLoopCount=0;
	UINT32 dwIntFlags=0;
	//UINT16 SpecialCtrlSts=0U;

	SMSC_ASSERT(pAdapter->LinkMode<=0x7FUL);

	pAdapter->LinkSpeed=LINK_OFF;
	pAdapter->LinkSettings=LINK_OFF;
	
	//auto-MDIX set.
	Phy_SetAutoMdixSts(pAdapter);
	
	Lan_MutexLock(pAdapter->MacPhyLock);
	//Reset PHY
	Phy_SetReg16(pAdapter,PHY_BCR,PHY_BCR_RESET_);
	dwLoopCount=0;
	do {
		SMSC_WARNING("%s()=>Wait %d ms untill Phy Reset completed.\n",__FUNCTION__, 10*dwLoopCount);
		osal_task_sleep(10);
		wTemp=Phy_GetReg16(pAdapter,PHY_BCR);
		dwLoopCount++;
	} while((dwLoopCount>1000) && (wTemp&PHY_BCR_RESET_));
	Lan_MutexUnlock(pAdapter->MacPhyLock);

	if(wTemp&PHY_BCR_RESET_) 
	{
		SMSC_WARNING("%s()=>PHY reset failed to complete.\n",__FUNCTION__);
		result = RET_FAILURE;
		goto DONE;
	}
	
	SMSC_WARNING("%s()=>PHY reset complete.\n",__FUNCTION__);
	osal_task_sleep(100);
	
	//Start Auto Negotiation.
	Phy_SetLink(pAdapter);

	//En Phy Int
	Phy_SetReg16(pAdapter, PHY_INT_MASK, (PHY_INT_MASK_ENERGY_ON_ \
		|PHY_INT_MASK_ANEG_COMP_|PHY_INT_MASK_REMOTE_FAULT_|PHY_INT_MASK_LINK_DOWN_));
DONE:
	
	return result;
}


void 
smsc9220_HSR(UINT32 sema_id)
{
	osal_semaphore_release(sema_id);
}


static void 
smsc9220_ISR(UINT32 param)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)param;

	HAL_GPIO_INT_CLEAR(SMSC9220_GPIO);			//Clear GPIO int status
	osal_interrupt_register_hsr((OSAL_T_HSR_PROC_FUNC_PTR)(smsc9220_HSR), (UINT32)pAdapter->IntSem);
}


void
smsc9220_task(UINT32 Para)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)Para;	
	
	UINT32 dwIntCfg=0;
	UINT32 dwIntSts=0;
	UINT32 dwIntEn=0;
	UINT32 dwIntBits=0;

	while(1)
	{
		UINT32 ret = osal_semaphore_capture(pAdapter->IntSem, /*OSAL_WAIT_FOREVER_TIME*/100);
		if(OSAL_E_OK != ret)
		{
			if(SMSC9220_POLAR == HAL_GPIO_BIT_GET(SMSC9220_GPIO))
			{
				libc_printf("%s()=>Int missed(0x%08x).\n", __FUNCTION__, Lan_GetRegDW(INT_STS));
			}
			else
				continue;
		}
		
#ifndef SMSC_UP_BUS						
		//Enter Mutex
		if(smsc_mutex_id.lock)
		{
			smsc_mutex_id.lock();
			//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
			HAL_GPIO_BIT_SET(SMSC_CS, 0);
		}
#endif //SMSC_UP_BUS

		//Int Handler
			
		dwIntSts=Lan_GetRegDW(INT_STS);		//int status
		dwIntEn=Lan_GetRegDW(INT_EN);		//int mask
		dwIntBits=dwIntSts&dwIntEn;
			
		pAdapter->LastIntStatus3=pAdapter->LastIntStatus2;
		pAdapter->LastIntStatus2=pAdapter->LastIntStatus1;
		pAdapter->LastIntStatus1=dwIntBits;	

		if(dwIntBits)
		{
			//SMSC_TRACE("%s()=>INT_STS(0x%08x) INT_EN(0x%08x)\n", __FUNCTION__, dwIntSts, dwIntEn);
			
			Tx_StartInterrupt(pAdapter,dwIntBits);
			//Rx_StopInterrupt(pAdapter,dwIntBits);
			Rx_Interrupt(pAdapter,dwIntBits);

			if(INT_EN_PHY_INT_EN_ & dwIntSts)
			{
				//SMSC_WARNING("%s()=>PHY interrupt.\n", __FUNCTION__);
				Phy_Interrupt(pAdapter);
				Lan_SetRegDW(INT_STS,INT_EN_PHY_INT_EN_);
			}
			
		}
		
#ifndef SMSC_UP_BUS		
		//Exit Mutex
		if(smsc_mutex_id.unlock)
		{
			//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
			HAL_GPIO_BIT_SET(SMSC_CS, 1);	
			smsc_mutex_id.unlock();
		}
#endif //SMSC_UP_BUS

	}

}


__ATTRIBUTE_REUSE_
RET_CODE smsc9220_attach(SMSC_CONFIG *cfg)
{
	struct net_device *dev;
	PPRIVATE_DATA pAdapter=NULL;
	UINT16 tmp_16;
	int i; 
	
	if(NULL==cfg)
		return ERR_FAILUE;

#ifdef SMSC_UP_BUS	
	if(cfg->en_gpio_setting)
	{
		SMSC9220_GPIO = cfg->int_gpio_position;
		SMSC_ADDR7 = cfg->a7_gpio_position;
		SMSC_FIFO_SEL = cfg->sel_gpio_position;
	}

	//Should Set GPIO-Addr before Access Any Regs.
	HAL_GPIO_BIT_DIR_SET(SMSC_FIFO_SEL, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SMSC_FIFO_SEL, 0);
	
	HAL_GPIO_BIT_DIR_SET(SMSC_ADDR7, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SMSC_ADDR7, g_smsc_addr7);
#else //SMSC_UP_BUS 	
	//init mutex for ATA and CI Share Pin.
	smsc_mutex_init();

	if(cfg->en_gpio_setting)
	{
		SMSC_CS = cfg->cs_gpio_position;

		SMSC_ADDR7 = cfg->a7_gpio_position;
		SMSC_ADDR6 = cfg->a6_gpio_position;
		SMSC_FIFO_SEL = cfg->sel_gpio_position;
		SMSC9220_GPIO = cfg->int_gpio_position;
		SMSC9220_POLAR = cfg->int_gpio_polar;
	}
	//Should Set GPIO-Addr before Access Any Regs.
	HAL_GPIO_BIT_DIR_SET(SMSC_FIFO_SEL, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SMSC_FIFO_SEL, 0);	

	HAL_GPIO_BIT_DIR_SET(SMSC_ADDR7, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SMSC_ADDR7, g_smsc_addr7);
	
	HAL_GPIO_BIT_DIR_SET(SMSC_ADDR6, HAL_GPIO_O_DIR);
	HAL_GPIO_BIT_SET(SMSC_ADDR6, g_smsc_addr6);
#endif //SMSC_UP_BUS	

	//alloc memory space for net device.
	dev = dev_alloc(smsc9220_name, HLD_DEV_TYPE_NET, sizeof(struct net_device));
	if (dev == NULL)
	{
		SMSC_WARNING("%s()=>alloc net device error!\n", __FUNCTION__);
		return ERR_NO_MEM;
	}

	//alloc memory space for NIC private structure.
	dev->priv=(void *)MALLOC(sizeof(PRIVATE_DATA));
	if(dev->priv==NULL) 
	{
		dev_free(dev);
		SMSC_WARNING("%s()=>alloc ethernet mac private memory error!\n", __FUNCTION__);
		return ERR_NO_MEM;
	}
	MEMSET(dev->priv,0,sizeof(PRIVATE_DATA));

	pAdapter=(PPRIVATE_DATA)(dev->priv);
	g_pAdapter = pAdapter;

	//Get Chip ID
	pAdapter->ChipId = sys_ic_get_chip_id();
#ifdef SMSC_UP_BUS
	if(SMSC9220_GPIO < 32)
		pAdapter->Irq = 9;
	else
	{
		if(ALI_M3329E == pAdapter->ChipId)
		{
			if(SMSC9220_GPIO<64)
				pAdapter->Irq = 24;
			else
				pAdapter->Irq = 31;
		}
		else
			pAdapter->Irq = 24;
	}
#else 
	if(ALI_S3602 == pAdapter->ChipId)
	{
		ATA_IO_BASE = _3602_IDE_IO_BASE;
		pAdapter->Irq= 8;
	}
	else
	{
		if(ALI_M3329E == pAdapter->ChipId)
		{
			HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
			HAL_GPIO_BIT_SET(SMSC_CS, 0);
		}
		
		ATA_IO_BASE = _3329_IDE_IO_BASE;
		if(SMSC9220_GPIO < 32)
			pAdapter->Irq = 9;
		else
		{
			if(ALI_M3329E == pAdapter->ChipId)
			{
				if(SMSC9220_GPIO<64)
					pAdapter->Irq = 24;
				else
					pAdapter->Irq = 31;
			}
			else
				pAdapter->Irq = 24;
		}
	}

	if(cfg->en_ata_setting)
	{
		ata_w32(ATA_PIOTCR, cfg->ata_timing);
	}	
	else
	{
		//ata_w32(ATA_PIOTCR, 0x02190900); //(cnt%2 ==0)
		//ata_w32(ATA_PIOTCR, 0x02190800); //(cnt%3 ==0)
		//ata_w32(ATA_PIOTCR, 0x02200800); //(cnt%5 ==0) 	
		ata_w32(ATA_PIOTCR, 0x02190900);
	}
#endif //SMSC_UP_BUS	

	if(cfg->en_mac_setting)
	{	
		pAdapter->MacAddrLo32 = 0;
		pAdapter->MacAddrHi16 =0;
		
		for(i = 0; i < 4; i ++)
			pAdapter->MacAddrLo32 |= (UINT32)(cfg->mac_addr[i]<<(8*i));

		for(; i < 6; i ++)
			pAdapter->MacAddrHi16 |= (UINT32)(cfg->mac_addr[i]<<(8*(i-4)));
	}

	dev->next = NULL;

	//init function point.
	//dev->attach = smsc9220_attach;
	dev->detach = smsc9220_detach;
	dev->open = smsc9220_open;
	dev->close = smsc9220_close;
	dev->ioctl = smsc9220_ioctl;
	dev->send_packet = smsc9220_send_packet;
	dev->callback = NULL;
	dev->get_info = smsc9220_get_info;
	dev->set_info = smsc9220_set_info;

	/* Add this device to queue */ 
	if (dev_register(dev) != RET_SUCCESS)
	{
		SMSC_WARNING("%()=>Register net device error!\n", __FUNCTION__);
		FREE(pAdapter);
		dev_free(dev);
		return RET_FAILURE;
	}

}


RET_CODE 
smsc9220_open(struct net_device*dev, void (*callback) (UINT32, UINT32))
{
	PPRIVATE_DATA pAdapter=NULL;
	RET_CODE result = SUCCESS;
	UINT32 dwIntCfg=0;
	UINT32 k;
	int cnt = 0;

	OSAL_T_CTSK task_param ;

	if(dev==NULL) 
	{
		SMSC_WARNING("%s()=>(dev==NULL)\n", __FUNCTION__);
		result=ERR_FAILUE;
		goto DONE;
	}
	pAdapter=(PPRIVATE_DATA)(dev->priv);
	if(pAdapter==NULL) 
	{
		SMSC_WARNING("%s()=>(pAdapter==NULL)\n", __FUNCTION__);
		result=ERR_FAILUE;
		goto DONE;
	}
	pAdapter->dev = dev;
	
#ifdef SMSC_UP_BUS
	smsc_spe_id = spe_get_dev(SPE_UP_ETH, 0x2f3fa0f1, &smsc_spe_map); 
	//smsc_spe_id = spe_get_dev(SPE_UP_ETH, 0x230e10c1, &smsc_spe_map); //135M
	SMSC_TRACE("%s()=>Get SPE ID(%d) Mapping Addr(0x%08x).\r\n",__FUNCTION__, smsc_spe_id, smsc_spe_map);

	pAdapter->TransferMode = SMSC_TRANSFER_DMA;
	//pAdapter->TransferMode = SMSC_TRANSFER_PIO;
#else
	//Enter Mutex
	if(smsc_mutex_id.lock)
	{
		smsc_mutex_id.lock();
		//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
		HAL_GPIO_BIT_SET(SMSC_CS, 0);
	}
	
	pAdapter->TransferMode = SMSC_TRANSFER_PIO;
#endif //SMSC_UP_BUS

	//chip verification.
	pAdapter->IdRev = Lan_GetRegDW(ID_REV);
	SMSC_TRACE("%s()=>IdRev(0x%08lX)\n", __FUNCTION__, pAdapter->IdRev);
	if(0x92200000 != pAdapter->IdRev)
	{
		SMSC_WARNING("%s()=>chip ID error.\n", __FUNCTION__);
		result=ERR_NO_DEV;
		goto DONE;
	}

	pAdapter->TxFifoSize = 0x00020000UL; 			// 2k bytes.

	pAdapter->DebugMode = 0x0UL; 				// not use debug mode
	//pAdapter->DebugMode = 0x7UL; 				// use debug mode

	if(pAdapter->MacAddrHi16 == 0)
		pAdapter->MacAddrHi16 = 0xFFFFFFFFUL; 	//decided by driver.
	
	pAdapter->PhyAddr = 1; 						//decided by driver.

	pAdapter->LinkMode = LINK_ADVERTISE; 			// advertise all(100M/10M, Full/Half duplex)	
	pAdapter->AutoMdix = 0x2U;					//En Auto Mdix.
	//pAdapter->AutoMdix = 0x0U;					//Straight.
	
	pAdapter->AfcConfig = 0xFFFFFFFFUL; 			//decided by driver. set to AFC_CFG register.

	pAdapter->UseRxCsum = FALSE;					//RxCOE
	pAdapter->UseTxCsum = FALSE;					//TxCOE
	
	//Specifies the minimum packet size for DMA to be used.
	pAdapter->DmaThreshold = PLATFORM_DMA_THRESHOLD;

	//mutex for MAC CSR accessing.
	pAdapter->MacPhyLock = osal_mutex_create();
	pAdapter->TransMutex = osal_mutex_create();
	pAdapter->RegMutex = osal_mutex_create();

	pAdapter->LinkStatus = FALSE;
	
	if ((pAdapter->IntSem = osal_semaphore_create(1))==OSAL_INVALID_ID) 
	{
		SMSC_WARNING("%s()=>semaphore create failure!\n", __FUNCTION__);
		result=ERR_FAILUE;
		goto DONE;
	}
	
	while(OSAL_E_OK!=osal_semaphore_capture(pAdapter->IntSem,1000))
		SMSC_WARNING("%s()=>Capture IntSem timeout !\n", __FUNCTION__);

	cnt = 0;
	while(0)
	{
		if(cnt%100 ==0)
			SMSC_WARNING("%s()=>cnt(%d)\n", __FUNCTION__, cnt);
		cnt ++;
		Lan_RegTest();
	}

	if(SUCCESS != Lan_Initialize(pAdapter))
	{
		SMSC_WARNING("%s()=>Failed lan_initialize.\n", __FUNCTION__);
		result=ERR_FAILUE;
		goto DONE;
	}

	//Interrupt Settings.
	//Disable All Interrupts & Clear Interrupt Status.
	Lan_SetRegDW(INT_EN,0);
	Lan_SetRegDW(INT_STS,0xFFFFFFFFUL);

	//Int Cfg=>IRQ polarity(Low)
	if(SMSC9220_POLAR == 1)
		dwIntCfg|=INT_CFG_IRQ_POL_;	//IRQ polarity(High)
	//dwIntCfg|=INT_CFG_IRQ_TYPE_;		//IRQ buffer type	
	dwIntCfg|=INT_CFG_IRQ_EN_;
	//dwIntCfg|=0x22000000;
	Lan_SetRegDW(INT_CFG,dwIntCfg);
	
	if(1)//get mac address
	{
		UINT32 dwHigh16=0;
		UINT32 dwLow32=0;
		UINT32 dwIntFlags=0;
		//Wait For Lock.
		Lan_MutexLock(pAdapter->MacPhyLock);

		//Mac_RegTest(pAdapter);
		
		if(pAdapter->MacAddrHi16==0xFFFFFFFF) 
		{//Set Mac Addr by OurSelves.FM-20090105
			dwHigh16=Mac_GetReg32(pAdapter,ADDRH);
			dwLow32=Mac_GetReg32(pAdapter,ADDRL);
			
			if((dwHigh16==0x0000FFFFUL)&&(dwLow32==0xFFFFFFFF))
			{
				dwHigh16=0x00000070UL;
				dwLow32=0x110F8000UL;
				Mac_SetReg32(pAdapter,ADDRH,dwHigh16);
				Mac_SetReg32(pAdapter,ADDRL,dwLow32);
				SMSC_TRACE("%s()=>Mac Address is set by default to 0x%04lX%08lX",
					__FUNCTION__,dwHigh16,dwLow32);
			} else {
				SMSC_TRACE("%s()=>Mac Address is read from LAN9220 as 0x%04lX%08lX",
					__FUNCTION__,dwHigh16,dwLow32);
			}
		} 
		else //Use Mac Address in ADDRH/ADDRL Registers.FM-20090105
		{
			SMSC_TRACE("%s()=>Mac Addr(0x%x%x).\n", __FUNCTION__, pAdapter->MacAddrHi16, pAdapter->MacAddrLo32);
			dwHigh16=pAdapter->MacAddrHi16;
			dwLow32=pAdapter->MacAddrLo32;
			Mac_SetReg32(pAdapter,ADDRH,dwHigh16);
			Mac_SetReg32(pAdapter,ADDRL,dwLow32);
			SMSC_TRACE("%s()=>Mac Address is set by parameter to 0x%04lX%08lX \n",
				__FUNCTION__,dwHigh16,dwLow32);
		}
		Lan_MutexUnlock(pAdapter->MacPhyLock);
		pAdapter->DevAddr[0]=LOBYTE(LOWORD(dwLow32));
		pAdapter->DevAddr[1]=HIBYTE(LOWORD(dwLow32));
		pAdapter->DevAddr[2]=LOBYTE(HIWORD(dwLow32));
		pAdapter->DevAddr[3]=HIBYTE(HIWORD(dwLow32));
		pAdapter->DevAddr[4]=LOBYTE(LOWORD(dwHigh16));
		pAdapter->DevAddr[5]=HIBYTE(LOWORD(dwHigh16));
	}

	if(SUCCESS != Phy_Initialize(pAdapter))
	{
		SMSC_WARNING("%s()=>Failed to initialize Phy.\n", __FUNCTION__);
		result=ERR_FAILED;
		goto DONE;
	}

	//Phy link test
	cnt = 0;
	while(0)
	{
		cnt ++;
		SMSC_WARNING("%s()=>Cnt(%d).\n",__FUNCTION__, cnt);
		Phy_CheckLink((UINT32)pAdapter);
	}

	//Phy_CheckLink((UINT32)pAdapter);

	Tx_Initialize(pAdapter);
	Rx_Initialize(pAdapter);

	//en PHY int.
	Lan_EnableInterrupt(pAdapter,INT_EN_PHY_INT_EN_);
	

	pAdapter->RxBuffer = NULL;
	pAdapter->RxBuffer = (UINT32 *)MALLOC(SMSC_PKT_BUFFER + 15);
	if(pAdapter->RxBuffer == NULL)
	{
		SMSC_WARNING("%s()=>Alloc Rx Buf Failed!\n", __FUNCTION__);
		goto DONE;
	}
	else
	{
		pAdapter->RxBuffer =(UINT32 *)(((UINT32)(pAdapter->RxBuffer) + SMSC_ALIGNMENT - 1) & ~(UINT32)(SMSC_ALIGNMENT-1));
		SMSC_WARNING("%s()=>RxBuffer(0x%08x)\n", __FUNCTION__, (UINT32)pAdapter->RxBuffer);
	}
	MEMSET(pAdapter->RxBuffer, 0x00, SMSC_PKT_BUFFER);

	//Dis Internal Timer Int.
	//Lan_EnableInterrupt(pAdapter,INT_EN_GPT_INT_EN_);

	//Set receiving callback function of TCPIP stack.   
	dev->callback = callback;

	// GPIO interrupt For SMSC9220 chip.
	HAL_GPIO_INT_SET(SMSC9220_GPIO, 1);			//GPIO Int En
	//HAL_GPIO_INT_SET(SMSC9220_GPIO, 0);			//GPIO Int Dis

	if(SMSC9220_POLAR == 0)
	{
		HAL_GPIO_INT_REDG_SET(SMSC9220_GPIO, 0);		//not Bring int at Rising edge
		HAL_GPIO_INT_FEDG_SET(SMSC9220_GPIO, 1);		//but Bring int at Failing edge
	}
	else
	{
		HAL_GPIO_INT_REDG_SET(SMSC9220_GPIO, 1);		//but Bring int at Rising edge
		HAL_GPIO_INT_FEDG_SET(SMSC9220_GPIO, 0);		//not Bring int at Failing edge
	}	
	
	HAL_GPIO_INT_CLEAR(SMSC9220_GPIO);			//Clear GPIO int status
	HAL_GPIO_BIT_DIR_SET(SMSC9220_GPIO,  0);		//Set GPIO direction to Input

	if(OSAL_E_OK!=osal_interrupt_register_lsr(pAdapter->Irq, smsc9220_ISR, (UINT32)pAdapter))
	{
		SMSC_WARNING("%s()=>GPIO ISR registered FAILED!\n", __FUNCTION__);
		result=ERR_FAILED;
		goto DONE;
	}

	pAdapter->RegisterIsr = TRUE;

	Lan_RegGetPrint(INT_EN);
	
	//create a task to update link mode.
	task_param.task   =  (FP)smsc9220_task;
	task_param.stksz  =  0x1000; 
	task_param.quantum = 10;
	task_param.itskpri = OSAL_PRI_NORMAL;
	task_param.para1= (UINT32)pAdapter;
	task_param.para2 = 0;
	task_param.name[0] = 'N';
	task_param.name[1] = 'E';
	task_param.name[2] = '9';

	pAdapter->TaskId = osal_task_create(&task_param);
	if(OSAL_INVALID_ID == pAdapter->TaskId)
	{
		SMSC_WARNING("%s()=>Create phy_checklink FAILED!\n", __FUNCTION__);
		goto DONE;
	}

	result=0;
DONE:
	if(result!=0) 
	{
		smsc9220_close(dev);
		SMSC_WARNING("%s()=>smsc9220_close()\n", __FUNCTION__);
	}

#ifndef SMSC_UP_BUS
	//Exit Mutex
	if(smsc_mutex_id.unlock)
	{
		//HAL_GPIO_BIT_DIR_SET(SMSC_CS, HAL_GPIO_O_DIR);
		HAL_GPIO_BIT_SET(SMSC_CS, 1);	
		smsc_mutex_id.unlock();
	}
#endif //SMSC_UP_BUS

	return result;
}


RET_CODE 
smsc9220_send_packet(struct net_device *dev, void *buf, UINT16 len)
{
	RET_CODE result = SUCCESS;
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)(dev->priv);
	int re = 0;

	if(pAdapter->LinkStatus == FALSE)
	{
		SMSC_WARNING("%s()=>Link's not ready.\n", __FUNCTION__);
		return ERR_FAILURE;
	}

	Lan_MutexLock(pAdapter->TransMutex);

	if(buf==NULL) {
		SMSC_WARNING("%()=>(buf==NULL).\n", __FUNCTION__);
		result=ERR_PARA;
		goto DONE;
	}
	if(dev==NULL) {
		SMSC_WARNING("%()=>(dev==NULL).\n", __FUNCTION__);
		result=ERR_PARA;
		goto DONE;
	}
	if(dev->priv==NULL) {
		SMSC_WARNING("%()=>(dev->priv==NULL).\n", __FUNCTION__);
		result=ERR_PARA;
		goto DONE;
	}
	
	re = Tx_SendBuf(pAdapter, buf, len);
	if(re != 0)
		result = ERR_FAILURE;
	
	Lan_MutexUnlock(pAdapter->TransMutex);

DONE:
	return result;
}


RET_CODE 
smsc9220_ioctl(struct net_device *dev, UINT32 cmd, UINT32 param)
{
	
	SMSC_TRACE("smsc9220_ioctl()=>Noting Done!\n");
	return RET_SUCCESS;
}


RET_CODE 
smsc9220_get_info(struct net_device *dev, UINT32 info_type, void *info_buf)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)(dev->priv);
	UINT32 ret = RET_SUCCESS;
	UINT8 ret_info[32];
	UINT32 ret_len = 0;

	SMSC_TRACE("%s()=>Net device get information, type = %d.\n", __FUNCTION__, info_type);

	switch(info_type)
	{
		case NET_GET_CURRENT_MAC :
			MEMCPY(ret_info, pAdapter->DevAddr, ETH_ALEN);
			ret_len = ETH_ALEN;
			break;
		case NET_GET_PERMANENT_MAC :
			MEMCPY(ret_info, pAdapter->DevAddr, ETH_ALEN);
			ret_len = ETH_ALEN;
			break;
			
		case NET_GET_LINK_STATUS :
			if(pAdapter->LinkStatus == TRUE)
				*((enum net_link_status *)ret_info) = NET_LINK_CONNECTED;
			else
				*((enum net_link_status *)ret_info) = NET_LINK_DISCONNECTED;
			ret_len = sizeof(enum net_link_status);
	    		break;
	
		case NET_GET_LINK_SPEED :
			if((pAdapter->LinkSpeed == LINK_SPEED_10FD) || (pAdapter->LinkSpeed == LINK_SPEED_10HD))
	    	  		*((enum net_link_speed *)ret_info) = NET_LINK_10MBPS;
			else
				*((enum net_link_speed *)ret_info) = NET_LINK_100MBPS;
			ret_len = sizeof(enum net_link_speed);	
	    		break;
			
		case NET_GET_LINK_MODE :
			if((pAdapter->LinkSpeed == LINK_SPEED_10FD) || (pAdapter->LinkSpeed == LINK_SPEED_100FD))
	    	  		*((enum net_link_mode *)ret_info) = NET_LINK_FULL;
			else
				*((enum net_link_mode *)ret_info) = NET_LINK_HALF;
			ret_len = sizeof(enum net_link_mode);	
	    		break;

		default :
			ret = RET_FAILURE;
	}
	if (ret == RET_SUCCESS)
	{
		MEMCPY(info_buf, ret_info, ret_len);
	}
	
	return ret;
}


RET_CODE 
smsc9220_set_info(struct net_device *dev, UINT32 info_type, void *info_buf)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)(dev->priv);
	UINT32 ret = RET_SUCCESS;
	SMSC_TRACE("%s()=>Net device set information, type = %d.\n", __FUNCTION__, info_type);

	switch(info_type)
	{
		case NET_SET_MAC :
			if((*((UINT32 *)info_buf + 1) & 0xFFFF8000UL)!=0)
			{
				SMSC_TRACE("%s()=>Bad Mac Address.\n");
				ret = RET_FAILURE;
			}
			else
			{
				pAdapter->MacAddrHi16 = *((UINT32 *)((UINT32)info_buf + 4));
				pAdapter->MacAddrLo32= *((UINT32 *)info_buf);
				SMSC_TRACE("%s()=>Mac Addr(0x%x%x).\n", __FUNCTION__, pAdapter->MacAddrHi16, pAdapter->MacAddrLo32);
			}
			break;
		case NET_SET_LINK_SPEED :
		case NET_SET_LINK_MODE :
		case NET_ADD_MULTICAST_ADDR :
		case NET_DEL_MULTICAST_ADDR :
			SMSC_TRACE("%s()=>Command not supported yet.\n", __FUNCTION__);
			break;

		default :
			ret = RET_FAILURE;
	}

	return ret;
}


RET_CODE 
smsc9220_close(struct net_device *dev)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)(dev->priv);

	Lan_DisableIRQ();

	SMSC_TRACE("smsc9220_detach()=>Detach net device driver.\n");
	if(pAdapter!=NULL)
	{
		if(pAdapter->MacPhyLock != OSAL_INVALID_ID)
		{
			SMSC_WARNING("%s()=>Delete mutex(MacPhyLock).\n", __FUNCTION__);
			osal_mutex_delete(pAdapter->MacPhyLock);
			pAdapter->MacPhyLock = OSAL_INVALID_ID;
		}

		if(pAdapter->TransMutex!= OSAL_INVALID_ID)
		{
			SMSC_WARNING("%s()=>Delete mutex(TransMutex).\n", __FUNCTION__);
			osal_mutex_delete(pAdapter->TransMutex);
			pAdapter->TransMutex = OSAL_INVALID_ID;
		}
		
		if(pAdapter->IntSem!= OSAL_INVALID_ID)
		{
			SMSC_WARNING("%s()=>Delete Sem(IntSem).\n", __FUNCTION__);
			osal_semaphore_delete(pAdapter->IntSem);
			pAdapter->IntSem = OSAL_INVALID_ID;
		}	
		
		if(pAdapter->RxBuffer!= NULL)
		{
			SMSC_WARNING("%s()=>Free Rx Buffer(RxBuffer).\n", __FUNCTION__);
			FREE(pAdapter->RxBuffer);
			pAdapter->RxBuffer = NULL;
		}

		if(pAdapter->RegisterIsr== TRUE)
		{
			//unregister GPIO interrupt handler. 
			osal_interrupt_unregister_lsr(8, smsc9220_ISR);
			pAdapter->RegisterIsr = FALSE;
		}
			
		if(pAdapter->TaskId != OSAL_INVALID_ID)
		{
			SMSC_WARNING("%s()=>Delete task(phy_checklink).\n", __FUNCTION__);
			osal_task_delete(pAdapter->TaskId);
		}
			
	}
}


RET_CODE 
smsc9220_detach(struct net_device *dev)
{
	PPRIVATE_DATA pAdapter = (PPRIVATE_DATA)(dev->priv);;

	SMSC_TRACE("smsc9220_detach: Detach net device driver.\n");
	if(pAdapter!=NULL)
	{
		MEMSET(pAdapter, 0x00, sizeof(PRIVATE_DATA));
		FREE(pAdapter);
		pAdapter = NULL;					
	}

	dev_free(dev);
	dev = NULL ;
	
	return RET_SUCCESS;
}


